package com.service.login.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import com.common.cache.CacheCommon;
import com.common.cache.CacheUtil;
import com.common.cipher.CipherType;
import com.common.cipher.CipherUtil;
import com.common.httputils.HttpUtils;
import com.common.lang.Assert;
import com.dao.repository.user.BasUserRepository;
import com.passcheck.user.BasUser;
import com.passcheck.wx.WxLoginBO;
import com.passcheck.wx.WxLoginDTO;
import com.passcheck.wx.WxLoginVO;
import com.service.login.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.sql.Timestamp;
import java.util.Optional;

/**
 * @author ZhangHaiWen
 * @title: LoginServiceImpl
 * @projectName minipasscheck
 * @description: 登录业务实现类
 * @date 2020/12/1714:31
 */
@Service(value = "loginService")
public class LoginServiceImpl implements LoginService {

    @Autowired
    private BasUserRepository basUserRepository;

       /**
   　　* @description: 登录实现类  {@link "https://blog.csdn.net/sinat_27938829/article/details/79935949"}
   　　* @param  wxLoginParam[code 微信小程序获取的code]
   　　* @return {@link Object 微信小程序得到返回密文后，需要根据RAS私钥进行解密，得到AES秘钥和AES加密的密文}
   　　* @throws
   　　* @author ZhangHaiWen
   　　* @version 2.0
   　　* @date 2020/12/17 14:48
   　　*/
    @Override
    @Transactional
    public Object login(WxLoginDTO wxLoginParam) {
        // 获取微信登录传参
        String code = wxLoginParam.getCode();
        Assert.notNull(code,"微信小程序获取的code不能为空");
        WxLoginBO wxLoginBO = build(code);
        // 发送get请求
        WxLoginVO httpResult = HttpUtils.Get(
                CacheUtil.get(CacheCommon.PROPERTIES_CACHE,"WX.URL.JSCODE2SESSION"),
                wxLoginBO,
                WxLoginVO.class);
        // 获取微信加密后的公钥
        String miniPubKeyEncrypt = wxLoginParam.getMiniPubKeyEncrypt();
        String miniAseKeyEncrypt = wxLoginParam.getMiniAseKeyEncrypt();
        // 使用微信公钥加密,私钥解密
        String miniAseKey = dncryptRsa(miniAseKeyEncrypt);
        String miniRSAPubKey = dncryptAes(miniPubKeyEncrypt, miniAseKey);
        // 用户Openid
        String openid = httpResult.getOpenid();
        BasUser findBasUser = new BasUser();
        findBasUser.setOpenId(openid);
        Example<BasUser> efindBasUser = Example.of(findBasUser);
        Optional<BasUser> opBasUser = basUserRepository.findOne(efindBasUser);
        // Openid 公钥 私钥保存,更新 数据库
        // 封装数据
        BasUser saveBasUser = new BasUser();
        saveBasUser.setOpenId(httpResult.getOpenid());
        saveBasUser.setAesKey(miniAseKey);
        saveBasUser.setRsaPubKey(miniRSAPubKey);
        Timestamp timestamp = new Timestamp(System.currentTimeMillis());
        if(!opBasUser.isPresent()){
            // 插入用户
            saveBasUser.setUserId(getUserId());
            saveBasUser.setAddTime(timestamp);
            saveBasUser.setUpdateTime(timestamp);
            basUserRepository.saveAndFlush(saveBasUser);
        }else{
            // 更新用户
            saveBasUser.setUpdateTime(timestamp);
            BasUser dbbasUser = opBasUser.get();
            // 对象属性拷贝，覆盖原对象
            BeanUtil.copyProperties(saveBasUser,dbbasUser,"id","addTime","userId");
            basUserRepository.saveAndFlush(dbbasUser);
        }
        WxLoginVO wxLoginVO = new WxLoginVO();
        wxLoginVO.setCiphertext(encryptAES(httpResult.getOpenid(),miniAseKey));
        wxLoginVO.setOpenid(null);
        // 保存数据库
        return wxLoginVO;
    }

   /**
   　　* @description: 封装请求参数
   　　* @param code 验证码
   　　* @return {@link WxLoginBO}
   　　* @throws
   　　* @author ZhangHaiWen
   　　* @version 2.0
   　　* @date 2020/12/28 12:41
   　　*/
    private WxLoginBO build(String code){
        // 请求业务封装
        WxLoginBO wxLoginBO = new WxLoginBO();
        wxLoginBO.setAppid(CacheUtil.get(CacheCommon.PROPERTIES_CACHE,"WX.APP.ID"));
        wxLoginBO.setGrant_type(CacheUtil.get(CacheCommon.PROPERTIES_CACHE,"WX.URL.GRANT_TYPE"));
        wxLoginBO.setSecret(CacheUtil.get(CacheCommon.PROPERTIES_CACHE,"WX.APP.SECRET"));
        wxLoginBO.setJs_code(code);
        return wxLoginBO;
    }

   /**
   　　* @description:
   　　* @param  获取用户id
   　　* @return {@link null}
   　　* @throws
   　　* @author ZhangHaiWen
   　　* @version 2.0
   　　* @date 2021/2/22 22:25
   　　*/
    private String getUserId(){
        return RandomUtil.randomNumbers(16);
    }

    /**
     　　* @description:  解密微信小程序的AES秘钥
     　　* @param [wxLoginVO]
     　　* @return {@link String}
     　　* @throws
     　　* @author ZhangHaiWen
     　　* @version 2.0
     　　* @date 2020/12/28 12:43
     　　*/
    private String dncryptRsa(String  miniAseKeyEncrypt){
        return CipherUtil.dncrypt(miniAseKeyEncrypt,
                CacheUtil.get(CacheCommon.PROPERTIES_CACHE,"RSA.SYS.PRIVATEKEY"),
                CipherType.RSA);
    }

    /**
     　　* @description:  解密微信小程序的公钥 使用微信AES秘钥
     　　* @param [wxLoginVO]
     　　* @return {@link String}
     　　* @throws
     　　* @author ZhangHaiWen
     　　* @version 2.0
     　　* @date 2020/12/28 12:43
     　　*/
    private String dncryptAes(String miniAseKeyEncrypt,String aseKey){
        return CipherUtil.dncrypt(miniAseKeyEncrypt,
                aseKey,
                CipherType.AES);
    }

    /**
     　　* @description:  加密数据
     　　* @param [wxLoginVO]
     　　* @return {@link String}
     　　* @throws
     　　* @author ZhangHaiWen
     　　* @version 2.0
     　　* @date 2020/12/28 12:43
     　　*/
    private String encryptAES(String content,String pubKey){
        return CipherUtil.encrypt(content,
                pubKey,
                CipherType.AES);
    }
}
